package com.itany.shop.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 石小俊
 * @date 2023年07月11日 14:54
 */
@WebServlet("*.file")
public class FileServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getServletPath();
        switch (path){
            case "/upload.file":
                upload(request,response);
                break;
            case "/download.file":
                download(request,response);
                break;
            case "/download2.file":
                download2(request,response);
                break;
            default:
                PrintWriter out = response.getWriter();
                out.println("<h1 style='color:red;'>您输入的请求有误,请重新输入</h1>");
                break;
        }
    }

    protected void download(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 使用二进制流的方式实现下载操作
        // 1.获取需要下载的服务器资源
        String path = getServletContext().getRealPath("/js/jquery-3.4.1.min.js");

        // 2.使用IO写出文件
        FileInputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(path);
            out = response.getOutputStream();
//            byte[] b = new byte[10240];
//            int i;
//            while((i = in.read(b)) != -1){
//                out.write(b,0,i);
//            }

            // 此时对于浏览器识别的资源默认做的是打开操作,而不是附件下载操作
            // 此时需要对下载的文件进行处理
            // 需要通过设置MIME协议的方式进行指定附件方式
            // 该协议通过不同的值指定不同的附件方式
            // 在Servlet中,以content-disposition属性进行控制
            // 该属性有两个值
            // 1.attachment:附件下载
            // 2.inline:在线打开
            // 由于下载是响应时的资源
            // 因此,需要在响应头信息中进行指定
//            response.setHeader("content-disposition","attachment");
            // 在该信息中,还可以自定义文件名
            // 属性值格式: 附件方式;filename=文件名
            response.setHeader("content-disposition","attachment;filename=jquery-3.4.1.min.js");

            byte[] b = new byte[10240];
            int i;
            while((i = in.read(b)) != -1){
                out.write(b,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    protected void download2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 使用二进制流的方式实现下载操作
        // 1.获取需要下载的服务器资源
        String path = getServletContext().getRealPath("/lib/jstl-1.2.jar");

        // 2.使用IO写出文件
        FileInputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(path);
            out = response.getOutputStream();

//            response.setHeader("content-disposition","attachment;filename=jstl-1.2.jar");
            // 如果文件名是一个中文,需要将其转换成ISO-8859-1字符集的中文,否则无法识别
//            response.setHeader("content-disposition","attachment;filename=中文.jar");
            response.setHeader("content-disposition",new String("attachment;filename=中文.jar".getBytes(),"ISO-8859-1"));
            byte[] b = new byte[10240];
            int i;
            while((i = in.read(b)) != -1){
                out.write(b,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    protected void upload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        String username = request.getParameter("username");
//        String file = request.getParameter("file");
//        System.out.println("username:"+username+",file:"+file);
        // 当使用二进制流数据进行传输之后,无法通过原有的方式获取对应的数据
        // 此时的数据是一个二进制流数据,必须通过流来操作

//        InputStream in = request.getInputStream();
//        byte[] b = new byte[10240];
//        int i = in.read(b);
//        System.out.println(new String(b,0,i));
        // 通过IO的方式可以获取到请求中点数据
        // 但是对这些数据的解析比较麻烦
        // 因此,可以使用第三方工具对这些数据进行解析

        // 注意点:工具做的仅仅只是解析操作,与上传无关

        // 使用第三方工具进行解析,获取对应工具的解析工厂,用于存放解析器
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 获取对应的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        try {
            // 进行解析
            List<FileItem> fileItems = upload.parseRequest(request);
            Map<String,FileItem> map = new HashMap<>();
            for(FileItem fileItem : fileItems){
//                System.out.println("文件名:"+fileItem.getName());
//                System.out.println("表单元素的内容或者文件内容:"+fileItem.getString("UTF-8"));
//                System.out.println("name属性:"+fileItem.getFieldName());
//                System.out.println(fileItem.getContentType());
//                if("username".equals(fileItem.getFieldName())){
//                    System.out.println("用户名:"+fileItem.getString());
//                }
//                if("file".equals(fileItem.getFieldName())){
//                    System.out.println("文件名:"+fileItem.getName());
//                    System.out.println("文件内容:"+fileItem.getString("UTF-8"));
//                }
                map.put(fileItem.getFieldName(),fileItem);
            }

            System.out.println("用户名:"+map.get("username").getString());
            System.out.println("文件内容:"+map.get("file").getString("UTF-8"));

            // 开始上传
            // 在服务器根目录创建一个upload目录
            // 在upload目录中以年月日为名创建子目录
            // 每天上传的文件上传到对应年月日的子目录中
            // 1.获取服务器根目录,在相对于根目录的地址中指定upload目录与年月日子目录的具体路径
            String path = getServletContext().getRealPath("/upload/"+new SimpleDateFormat("yyyyMMdd").format(new Date()));
            // 2.创建该路径所涉及的所有目录
            File f = new File(path);
            f.mkdirs();

            // 3.上传文件
            FileItem file = map.get("file");
            // 文件名可能存在中文,需要处理
            String fileName = new String(file.getName().getBytes(),"UTF-8");

            // 不允许上传jsp文件,其他文件正常上传
            if(fileName.endsWith(".jsp")){
                request.setAttribute("uploadMsg","不允许上传jsp文件");
                request.getRequestDispatcher("/jsp/upload.jsp").forward(request,response);
                return;
            }

            // 文件名可能存在重名的,可以为文件重命名,在每一个文件后加一个毫秒数的后缀
            fileName = fileName.substring(0,fileName.lastIndexOf(".")) + "-" + new Date().getTime()+fileName.substring(fileName.lastIndexOf("."));

            file.write(new File(path,fileName));

        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
